package principal;

/**
 * Javier Abell�n, 24 Mayo 2006
 * Acci�n para dibujo de trazos.
 */

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.LinkedList;

import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * Construye trazos seg�n se le avisa de arrastre de rat�n.
 * 
 * @author Chuidiang.
 */
public class PintaTrazo implements InterfaceArrastrarRaton {

	/*
	 * Puede tomar 4 valores: 1: Modo principal: Reconoce actividades, nexos,
	 * documentos y eventos. 2: Modo escritura 3: Modo evento: reconoce
	 * sobres(rectangulos) o relojes (circulos) 4: Modo nexos: Reconoce + y x.
	 */

	public final static int MODO_PRINCIPAL = 1;
	public final static int MODO_ESCRITURA = 2;
	public final static int MODO_EVENTO = 3;
	public final static int MODO_DECISION = 4;

	private int modo;

	private boolean borrando;

	public LinkedList<Integer> ultimosMovimientos;

	private IFabrica fabrica;

	private int paso;

	IReconocedorFormas reconocedor;

        /** Lista de trazos */
	int indice = 0;

	/** Lista de formas ya reconocidas */
	private LinkedList<Calle> calles = new LinkedList<Calle>();

	/** Lista de formas ya reconocidas */
	private LinkedList<Forma> formas = new LinkedList<Forma>();

	private LinkedList<Trazo> trazos;

	/** Lista de trazos dibujados */
	private LinkedList<Linea> lineas = new LinkedList<Linea>();

	/**
	 * Trazo que se est� construyendo actualmente
	 * 
	 * @uml.property name="trazoActual"
	 * @uml.associationEnd
	 */
	private Trazo trazoActual = null;

	/**
	 * Lienzo de dibujo, necesario para llamar a repaint() seg�n se va
	 * construyendo un nuevo trazo.
	 */
	private Component lienzo;

	/** Color del que se est� dibujando el trazo actual */
	private Color colorActual = Color.black;

	/** Esta a true cuando se esta pintando en ese momento en el panel */
	private boolean pintando;

	public boolean isPintando() {
		return pintando;
	}

	/**
	 * Construye una instancia de esta clase, guardandose los par�mtros que le
	 * pasan.
	 * 
	 * @param trazos
	 *            Lista donde ir� metiendo los nuevos trazos que se creen.
	 * @param lienzo
	 *            Llamar� a repaint() de este componente seg�n se va
	 *            construyendo un trazo.
	 */
	public PintaTrazo(LinkedList<Trazo> trazos, LinkedList<Forma> formas,
			LinkedList<Linea> lineas, LinkedList<Calle> calles, Component lienzo) {
		this.trazos = trazos;
		this.lienzo = lienzo;
		this.reconocedor = new ReconocedorFormasPrincipales(calles, formas,
				lineas);
		this.modo = 1;
		this.formas = formas;
		this.lineas = lineas;
		this.calles = calles;
		this.pintando = false;
		this.paso = 0;
		this.fabrica = new FabricaFormaPrincipal(calles, formas, lineas);
		borrando = false;
		ultimosMovimientos = new LinkedList<Integer>();
	}

	public int getPaso() {
		return paso;
	}

	public void setPaso(int paso) {
		this.paso = paso;
	}

	/**
	 * Crea un trazo nuevo y le pone como primer punto x,y.
	 */
	public void comienzaArrastra(int x, int y) {
		pintando = true;
		trazoActual = new Trazo();
		trazoActual.setColor(colorActual);
		trazoActual.addPunto(x, y);
		trazos.add(trazoActual);
		lienzo.repaint();
	}

	/** A�ade un nuevo punto al trazo actual */
	public void arrastra(int xAntigua, int yAntigua, int xNueva, int yNueva) {
		pintando = true;
		trazoActual.addPunto(xNueva, yNueva);
		indice++;
		lienzo.repaint();
	}

	/** Marca que ya no hay trazo actual */
	public void finalizaArrastra(int x, int y) {
		trazoActual = null;
	}

	/**
	 * Guarda el color para el pr�ximo trazo que se dibuje
	 * 
	 * @uml.property name="colorActual"
	 */
	public void setColorActual(Color colorActual) {
		this.colorActual = colorActual;
	}

	@Override
	public void sueltaRaton(MouseEvent e) {
		// Borro el trazo dibujado
		if (modo != MODO_ESCRITURA) {
			//trazoActual.setColor(Color.WHITE);
			lienzo.repaint();
		}
		pintando = false;
		

		boolean reconocido = false;

		/*
		 * Compruebo si es una forma principal: una calle,
        	 * una linea, un documento o cualquier forma dentro
		 * de una calle
		 */
		if (modo == MODO_PRINCIPAL) {// Estoy reconociendo una de las formas principales
			reconocido = true;
			reconocedor.setTrazo(trazoActual);
			fabrica.setTrazo(trazoActual);

                        int a = reconocedor.reconoceTrazo();
			fabrica.fabricaForma(a);

        		if (a == 5) {
                            ultimosMovimientos.add(new Integer(2));
			} else  
                            if (a == 6)
                                ultimosMovimientos.add(new Integer(1));
                            else
                                ultimosMovimientos.add(new Integer(3));

                            if (a == 3) {// He pintado un circulo
                                modo = MODO_EVENTO;
                                reconocedor = new ReconocedorEventos();
				fabrica = new FabricaEventos(formas);
                            }
								
                            if (a == 1 || a == 6) {// He pintado una calle o una actividad, entro en modo escritura
                                System.out.println("he terminado de pintar la cale, estoy pintando ="+pintando+", modo: "+modo);
				lienzo.update(lienzo.getGraphics());
				modo = MODO_ESCRITURA;
				System.out.println("estoy pintando ="+pintando+", modo: "+modo);
				reconocedor = new ReconocedorEscritura();
				fabrica = new FabricaEscritura(formas, calles, a);
                            }
                            
                            if (a == 4) {
                                modo = MODO_DECISION;
				reconocedor = new ReconocedorDecision();
				fabrica = new FabricaDecision(formas);
                            }
                        }
			
                if (modo == MODO_EVENTO && !reconocido) {
                    reconocedor.setTrazo(trazoActual);

                    int a = reconocedor.reconoceTrazo();
                    fabrica.fabricaForma(a);

                    modo = MODO_PRINCIPAL;
                    reconocedor = new ReconocedorFormasPrincipales(calles, formas, lineas);
                    fabrica = new FabricaFormaPrincipal(calles, formas, lineas);
                }

		if (modo == MODO_DECISION && !reconocido) {
                    reconocedor.setTrazo(trazoActual);
                    fabrica.setTrazo(trazoActual);

                    int a = reconocedor.reconoceTrazo();
                    fabrica.fabricaForma(a);

                    modo = MODO_PRINCIPAL;
                    reconocedor = new ReconocedorFormasPrincipales(calles, formas, lineas);
                    fabrica = new FabricaFormaPrincipal(calles,	formas, lineas);
                }

                lienzo.repaint();
        }


        public void imprimirImagen() throws ImageFormatException, IOException {
            int width = 1160;
            int height = lienzo.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            lienzo.repaint();
            lienzo.paintAll(g);
            g.dispose();


            Image aux = image;
            BufferedImage tnsImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = tnsImg.createGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics2D.drawImage(aux, 0, 0, width, height, null);

            Calendar cal = Calendar.getInstance();
            int d = cal.get(Calendar.DATE);
            int h = cal.get(Calendar.HOUR_OF_DAY);
            int m = cal.get(Calendar.MINUTE);
            int s = cal.get(Calendar.SECOND);

            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("C:\\BPMNS/imag" + d + h + m + s + ".jpg"));
            //creamos el "parseador" para guardar la imagen en formato JPG
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(tnsImg);

            //Asignamos la calidad con la que se va a guardar la imagen de 0-100
            param.setQuality(50, false);
            encoder.setJPEGEncodeParam(param);
            encoder.encode(tnsImg);
            out.close();
        }


	public void setPintando(boolean b) {
		pintando = false;
	}

	public int getModo() {
		return modo;
	}

	public void finEscritura() {
		String c = "";
		try {
			c = reconocedor.reconoceEscritura(lienzo);
		} catch (ImageFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		((FabricaEscritura) fabrica).fabricaForma(c);

		pintando = false;
		reconocedor = new ReconocedorFormasPrincipales(calles, formas, lineas);
		fabrica = new FabricaFormaPrincipal(calles, formas, lineas);
		modo = MODO_PRINCIPAL;

		lienzo.repaint();
	}

	public boolean isBorrando() {
		return borrando;
	}

	public void setBorrando(boolean borrando) {
		this.borrando = borrando;
	}

	public void borrarUltimo() {
		Integer a = ultimosMovimientos.removeLast();
		if (a == 1)// es una calle
			calles.removeLast();
		if (a == 2) {// es una linea
			System.out.println("Lo ultimo es una raya y la voy a borrar");
			lineas.removeLast();
		}
		if (a == 3)// es una forma
			formas.removeLast();
		modo = MODO_PRINCIPAL;
		reconocedor = new ReconocedorFormasPrincipales(calles, formas, lineas);
		fabrica = new FabricaFormaPrincipal(calles, formas, lineas);

		borrando = true;
		lienzo.repaint();
		lienzo.repaint();
	}

	public void borrarTodo() {
		calles.clear();
		lineas.clear();
		formas.clear();
		modo = MODO_PRINCIPAL;
		reconocedor = new ReconocedorFormasPrincipales(calles, formas, lineas);
		fabrica = new FabricaFormaPrincipal(calles, formas, lineas);

		borrando = true;
		lienzo.repaint();
	}

}
